/**
 * Copyright (C) @2014 Webank Group Holding Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.webank.framework.data.jedis.pool;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisShardInfo;
import redis.clients.jedis.ScanResult;
import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.SortingParams;
import redis.clients.jedis.Tuple;
import redis.clients.util.Pool;

/**
 * 对ShardedJedis封装，支持ha.
 * 
 * @author jonyang
 *
 */
public class WeBankShardedJedis {
	private ShardedJedis sharedJedis;

	private List<JedisShardInfo> sharedJedisList;

	public WeBankShardedJedis(ShardedJedis sharedJedis) {
		this.sharedJedis = sharedJedis;
		Collection<JedisShardInfo> allShardInfo = sharedJedis.getAllShardInfo();
		this.sharedJedisList = new ArrayList<JedisShardInfo>(allShardInfo);
	}

	protected Pool<ShardedJedis> dataSource = null;

	public Collection<JedisShardInfo> getAllShardInfo() {
		Collection<JedisShardInfo> allShardInfo = sharedJedis.getAllShardInfo();
		return allShardInfo;
	}

	/**
	 * @return the sharedJedis
	 */
	public ShardedJedis getSharedJedis() {
		return sharedJedis;
	}

	public Jedis getNext(Jedis j) {
		int i = 0;
		for (; i < this.sharedJedisList.size(); i++) {
			JedisShardInfo tmp = this.sharedJedisList.get(i);
			if (j != null && j.getClient() != null && tmp != null
					&& (j.getClient().getHost().equals(tmp.getHost()))
					&& (j.getClient().getPort() == tmp.getPort())) {
				break;
			}
		}

		Jedis k = this.sharedJedisList.get(
				(i + 1) % this.sharedJedisList.size()).createResource();
		return k;
	}

	// public String set(String key, String value) {
	// Jedis j = sharedJedis.getShard(key);
	// try {
	// return j.set(key, value);
	// } catch (Exception e) {
	// Jedis k = getNext(j);
	// return k.set(key, value);
	// }
	// }
	//
	// public String set(String key, String value, String nxxx, String expx,
	// long time) {
	// Jedis j = sharedJedis.getShard(key);
	// try {
	// return j.set(key, value, nxxx, expx, time);
	// } catch (Exception e) {
	// Jedis k = getNext(j);
	// return k.set(key, value, nxxx, expx, time);
	// }
	// }

	public String get(String key) {
		Jedis j = sharedJedis.getShard(key);
		try {
			return j.get(key);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.get(key);
		}
	}

	public String echo(String string) {
		Jedis j = sharedJedis.getShard(string);
		try {
			return j.echo(string);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.echo(string);
		}
	}

	public Boolean exists(String key) {
		Jedis j = sharedJedis.getShard(key);
		try {
			return j.exists(key);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.exists(key);
		}
	}

	public String type(String key) {
		Jedis j = sharedJedis.getShard(key);
		try {
			return j.type(key);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.type(key);
		}
	}

	public Long expire(String key, int seconds) {
		Jedis j = sharedJedis.getShard(key);
		try {
			return j.expire(key, seconds);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.expire(key, seconds);
		}
	}

	public Long expireAt(String key, long unixTime) {
		Jedis j = sharedJedis.getShard(key);
		try {
			return j.expireAt(key, unixTime);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.expireAt(key, unixTime);
		}
	}

	public Long ttl(String key) {
		Jedis j = sharedJedis.getShard(key);
		try {
			return j.ttl(key);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.ttl(key);
		}
	}

	// public Boolean setbit(String key, long offset, boolean value) {
	// Jedis j = sharedJedis.getShard(key);
	// try {
	// return j.setbit(key, offset, value);
	// } catch (Exception e) {
	// Jedis k = getNext(j);
	// return k.setbit(key, offset, value);
	// }
	// }

	// public Boolean setbit(String key, long offset, String value) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.setbit(key, offset, value);
	// }

	public Boolean getbit(String key, long offset) {
		Jedis j = sharedJedis.getShard(key);
		try {
			return j.getbit(key, offset);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.getbit(key, offset);
		}
	}

	// public Long setrange(String key, long offset, String value) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.setrange(key, offset, value);
	// }

	public String getrange(String key, long startOffset, long endOffset) {
		Jedis j = sharedJedis.getShard(key);
		try {
			return j.getrange(key, startOffset, endOffset);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.getrange(key, startOffset, endOffset);
		}
	}

	public String getSet(String key, String value) {
		Jedis j = sharedJedis.getShard(key);
		try {
			return j.getSet(key, value);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.getSet(key, value);
		}
	}

	// public Long setnx(String key, String value) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.setnx(key, value);
	// }
	//
	// public String setex(String key, int seconds, String value) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.setex(key, seconds, value);
	// }

	// public List<String> blpop(String arg) {
	// Jedis j = sharedJedis.getShard(arg);
	// return j.blpop(arg);
	// }
	//
	// public List<String> blpop(int timeout, String key) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.blpop(timeout, key);
	// }
	//
	// public List<String> brpop(String arg) {
	// Jedis j = sharedJedis.getShard(arg);
	// return j.brpop(arg);
	// }
	//
	// public List<String> brpop(int timeout, String key) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.brpop(timeout, key);
	// }
	//
	// public Long decrBy(String key, long integer) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.decrBy(key, integer);
	// }
	//
	// public Long decr(String key) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.decr(key);
	// }
	//
	// public Long incrBy(String key, long integer) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.incrBy(key, integer);
	// }
	//
	// public Double incrByFloat(String key, double integer) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.incrByFloat(key, integer);
	// }
	//
	// public Long incr(String key) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.incr(key);
	// }

	// public Long append(String key, String value) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.append(key, value);
	// }

	// public String substr(String key, int start, int end) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.substr(key, start, end);
	// }

	// public Long hset(String key, String field, String value) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.hset(key, field, value);
	// }

	public String hget(String key, String field) {
		Jedis j = sharedJedis.getShard(key);
		try {
			return j.hget(key, field);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.hget(key, field);
		}
	}

	// public Long hsetnx(String key, String field, String value) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.hsetnx(key, field, value);
	// }
	//
	// public String hmset(String key, Map<String, String> hash) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.hmset(key, hash);
	// }

	public List<String> hmget(String key, String... fields) {
		Jedis j = sharedJedis.getShard(key);
		try {
			return j.hmget(key, fields);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.hmget(key, fields);
		}
	}

	// public Long hincrBy(String key, String field, long value) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.hincrBy(key, field, value);
	// }
	//
	// public Double hincrByFloat(String key, String field, double value) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.hincrByFloat(key, field, value);
	// }

	public Boolean hexists(String key, String field) {
		Jedis j = sharedJedis.getShard(key);
		try {
			return j.hexists(key, field);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.hexists(key, field);
		}
	}

	// public Long del(String key) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.del(key);
	// }
	//
	// public Long hdel(String key, String... fields) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.hdel(key, fields);
	// }

	public Long hlen(String key) {
		Jedis j = sharedJedis.getShard(key);
		try {
			return j.hlen(key);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.hlen(key);
		}
	}

	public Set<String> hkeys(String key) {
		Jedis j = sharedJedis.getShard(key);
		try {
			return j.hkeys(key);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.hkeys(key);
		}
	}

	public List<String> hvals(String key) {
		Jedis j = sharedJedis.getShard(key);
		try {
			return j.hvals(key);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.hvals(key);
		}
	}

	public Map<String, String> hgetAll(String key) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.hgetAll(key);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.hgetAll(key);
		}
	}

	// public Long rpush(String key, String... strings) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.rpush(key, strings);
	// }
	//
	// public Long lpush(String key, String... strings) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.lpush(key, strings);
	// }
	//
	// public Long lpushx(String key, String... string) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.lpushx(key, string);
	// }

	public Long strlen(final String key) {
		Jedis j = sharedJedis.getShard(key);
		try {
			return j.strlen(key);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.strlen(key);
		}
	}

	// public Long move(String key, int dbIndex) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.move(key, dbIndex);
	// }
	//
	// public Long rpushx(String key, String... string) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.rpushx(key, string);
	// }

	// public Long persist(final String key) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.persist(key);
	// }

	public Long llen(String key) {
		Jedis j = sharedJedis.getShard(key);
		try {
			return j.llen(key);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.llen(key);
		}
	}

	public List<String> lrange(String key, long start, long end) {
		Jedis j = sharedJedis.getShard(key);
		try {
			return j.lrange(key, start, end);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.lrange(key, start, end);
		}
	}

	// public String ltrim(String key, long start, long end) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.ltrim(key, start, end);
	// }

	public String lindex(String key, long index) {
		Jedis j = sharedJedis.getShard(key);
		try {
			return j.lindex(key, index);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.lindex(key, index);
		}
	}

	// public String lset(String key, long index, String value) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.lset(key, index, value);
	// }

	// public Long lrem(String key, long count, String value) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.lrem(key, count, value);
	// }
	//
	// public String lpop(String key) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.lpop(key);
	// }
	//
	// public String rpop(String key) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.rpop(key);
	// }
	//
	// public Long sadd(String key, String... members) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.sadd(key, members);
	// }

	public Set<String> smembers(String key) {
		Jedis j = sharedJedis.getShard(key);
		try {
			return j.smembers(key);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.smembers(key);
		}
	}

	// public Long srem(String key, String... members) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.srem(key, members);
	// }
	//
	// public String spop(String key) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.spop(key);
	// }

	public Long scard(String key) {
		Jedis j = sharedJedis.getShard(key);
		try {
			return j.scard(key);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.scard(key);
		}
	}

	public Boolean sismember(String key, String member) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.sismember(key, member);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.sismember(key, member);
		}
	}

	public String srandmember(String key) {
		Jedis j = sharedJedis.getShard(key);
		try {
			return j.srandmember(key);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.srandmember(key);
		}
	}

	public List<String> srandmember(String key, int count) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.srandmember(key, count);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.srandmember(key, count);
		}
	}

	// public Long zadd(String key, double score, String member) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.zadd(key, score, member);
	// }
	//
	// public Long zadd(String key, Map<String, Double> scoreMembers) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.zadd(key, scoreMembers);
	// }

	public Set<String> zrange(String key, long start, long end) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.zrange(key, start, end);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.zrange(key, start, end);
		}
	}

	// public Long zrem(String key, String... members) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.zrem(key, members);
	// }
	//
	// public Double zincrby(String key, double score, String member) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.zincrby(key, score, member);
	// }

	public Long zrank(String key, String member) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.zrank(key, member);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.zrank(key, member);
		}
	}

	public Long zrevrank(String key, String member) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.zrevrank(key, member);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.zrevrank(key, member);
		}
	}

	public Set<String> zrevrange(String key, long start, long end) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.zrevrange(key, start, end);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.zrevrange(key, start, end);
		}
	}

	public Set<Tuple> zrangeWithScores(String key, long start, long end) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.zrangeWithScores(key, start, end);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.zrangeWithScores(key, start, end);
		}
	}

	public Set<Tuple> zrevrangeWithScores(String key, long start, long end) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.zrevrangeWithScores(key, start, end);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.zrevrangeWithScores(key, start, end);
		}
	}

	public Long zcard(String key) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.zcard(key);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.zcard(key);
		}
	}

	public Double zscore(String key, String member) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.zscore(key, member);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.zscore(key, member);
		}
	}

	public List<String> sort(String key) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.sort(key);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.sort(key);
		}
	}

	public List<String> sort(String key, SortingParams sortingParameters) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.sort(key, sortingParameters);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.sort(key, sortingParameters);
		}
	}

	public Long zcount(String key, double min, double max) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.zcount(key, min, max);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.zcount(key, min, max);
		}
	}

	public Long zcount(String key, String min, String max) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.zcount(key, min, max);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.zcount(key, min, max);
		}
	}

	public Set<String> zrangeByScore(String key, double min, double max) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.zrangeByScore(key, min, max);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.zrangeByScore(key, min, max);
		}
	}

	public Set<String> zrevrangeByScore(String key, double max, double min) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.zrevrangeByScore(key, max, min);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.zrevrangeByScore(key, max, min);
		}
	}

	public Set<String> zrangeByScore(String key, double min, double max,
			int offset, int count) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.zrangeByScore(key, min, max, offset, count);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.zrangeByScore(key, min, max, offset, count);
		}
	}

	public Set<String> zrevrangeByScore(String key, double max, double min,
			int offset, int count) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.zrevrangeByScore(key, max, min, offset, count);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.zrevrangeByScore(key, max, min, offset, count);
		}
	}

	public Set<Tuple> zrangeByScoreWithScores(String key, double min, double max) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.zrangeByScoreWithScores(key, min, max);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.zrangeByScoreWithScores(key, min, max);
		}
	}

	public Set<Tuple> zrevrangeByScoreWithScores(String key, double max,
			double min) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.zrevrangeByScoreWithScores(key, max, min);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.zrevrangeByScoreWithScores(key, max, min);
		}
	}

	public Set<Tuple> zrangeByScoreWithScores(String key, double min,
			double max, int offset, int count) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.zrangeByScoreWithScores(key, min, max, offset, count);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.zrangeByScoreWithScores(key, min, max, offset, count);
		}
	}

	public Set<Tuple> zrevrangeByScoreWithScores(String key, double max,
			double min, int offset, int count) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.zrevrangeByScoreWithScores(key, max, min, offset, count);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.zrevrangeByScoreWithScores(key, max, min, offset, count);
		}
	}

	public Set<String> zrangeByScore(String key, String min, String max) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.zrangeByScore(key, min, max);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.zrangeByScore(key, min, max);
		}
	}

	public Set<String> zrevrangeByScore(String key, String max, String min) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.zrevrangeByScore(key, max, min);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.zrevrangeByScore(key, max, min);
		}
	}

	public Set<String> zrangeByScore(String key, String min, String max,
			int offset, int count) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.zrangeByScore(key, min, max, offset, count);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.zrangeByScore(key, min, max, offset, count);
		}
	}

	public Set<String> zrevrangeByScore(String key, String max, String min,
			int offset, int count) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.zrevrangeByScore(key, max, min, offset, count);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.zrevrangeByScore(key, max, min, offset, count);
		}
	}

	public Set<Tuple> zrangeByScoreWithScores(String key, String min, String max) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.zrangeByScoreWithScores(key, min, max);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.zrangeByScoreWithScores(key, min, max);
		}
	}

	public Set<Tuple> zrevrangeByScoreWithScores(String key, String max,
			String min) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.zrevrangeByScoreWithScores(key, max, min);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.zrevrangeByScoreWithScores(key, max, min);
		}
	}

	public Set<Tuple> zrangeByScoreWithScores(String key, String min,
			String max, int offset, int count) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.zrangeByScoreWithScores(key, min, max, offset, count);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.zrangeByScoreWithScores(key, min, max, offset, count);
		}
	}

	public Set<Tuple> zrevrangeByScoreWithScores(String key, String max,
			String min, int offset, int count) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.zrevrangeByScoreWithScores(key, max, min, offset, count);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.zrevrangeByScoreWithScores(key, max, min, offset, count);
		}
	}

	public Long zremrangeByRank(String key, long start, long end) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.zremrangeByRank(key, start, end);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.zremrangeByRank(key, start, end);
		}
	}

	public Long zremrangeByScore(String key, double start, double end) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.zremrangeByScore(key, start, end);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.zremrangeByScore(key, start, end);
		}
	}

	public Long zremrangeByScore(String key, String start, String end) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.zremrangeByScore(key, start, end);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.zremrangeByScore(key, start, end);
		}
	}

	public Long zlexcount(final String key, final String min, final String max) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.zlexcount(key, min, max);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.zlexcount(key, min, max);
		}
	}

	public Set<String> zrangeByLex(final String key, final String min,
			final String max) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.zrangeByLex(key, min, max);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.zrangeByLex(key, min, max);
		}
	}

	public Set<String> zrangeByLex(final String key, final String min,
			final String max, final int offset, final int count) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.zrangeByLex(key, min, max, offset, count);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.zrangeByLex(key, min, max, offset, count);
		}
	}

	public Long zremrangeByLex(final String key, final String min,
			final String max) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.zremrangeByLex(key, min, max);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.zremrangeByLex(key, min, max);
		}
	}

	// public Long linsert(String key, LIST_POSITION where, String pivot,
	// String value) {
	// Jedis j = getShard(key);
	// return j.linsert(key, where, pivot, value);
	// }

	public Long bitcount(final String key) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.bitcount(key);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.bitcount(key);
		}
	}

	public Long bitcount(final String key, long start, long end) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.bitcount(key, start, end);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.bitcount(key, start, end);
		}
	}

	// @Deprecated
	// /**
	// * This method is deprecated due to bug (scan cursor should be unsigned
	// long)
	// * And will be removed on next major release
	// * @see https://github.com/xetorthio/jedis/issues/531
	// */
	// public ScanResult<Entry<String, String>> hscan(String key, int cursor) {
	// Jedis j = sharedJedis.getShard(key);
	// return j.hscan(key, cursor);
	// }

	// @Deprecated
	// /**
	// * This method is deprecated due to bug (scan cursor should be unsigned
	// long)
	// * And will be removed on next major release
	// * @see https://github.com/xetorthio/jedis/issues/531
	// */
	// public ScanResult<String> sscan(String key, int cursor) {
	// Jedis j = getShard(key);
	// return j.sscan(key, cursor);
	// }

	// @Deprecated
	// /**
	// * This method is deprecated due to bug (scan cursor should be unsigned
	// long)
	// * And will be removed on next major release
	// * @see https://github.com/xetorthio/jedis/issues/531
	// */
	// public ScanResult<Tuple> zscan(String key, int cursor) {
	// Jedis j = getShard(key);
	// return j.zscan(key, cursor);
	// }

	public ScanResult<Entry<String, String>> hscan(String key,
			final String cursor) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.hscan(key, cursor);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.hscan(key, cursor);
		}
	}

	public ScanResult<String> sscan(String key, final String cursor) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.sscan(key, cursor);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.sscan(key, cursor);
		}
	}

	public ScanResult<Tuple> zscan(String key, final String cursor) {
		Jedis j = sharedJedis.getShard(key);

		try {
			return j.zscan(key, cursor);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.zscan(key, cursor);
		}
	}

	public void close() {
		sharedJedis.close();
	}

	public void setDataSource(Pool<ShardedJedis> shardedJedisPool) {
		sharedJedis.setDataSource(shardedJedisPool);
	}

	public void resetState() {
		sharedJedis.resetState();
	}

	// public Long pfadd(String key, String... elements) {
	// Jedis j = getShard(key);
	// return j.pfadd(key, elements);
	// }

	public long pfcount(String key) {
		Jedis j = sharedJedis.getShard(key);
		try {
			return j.pfcount(key);
		} catch (Exception e) {
			Jedis k = getNext(j);
			return k.pfcount(key);
		}

	}

}
